from typing import Optional
from pydantic import BaseModel
import urllib.parse as urlparse


'''
DID Parameters
https://www.w3.org/TR/did-core/#did-parameters
service	:Identifies a service from the DID document by service ID. If present, the associated value MUST be an ASCII string.
relativeRef	:A relative URI reference according to RFC3986 Section 4.2 that identifies a resource at a service endpoint, which is selected from a DID document by using the service parameter. If present, the associated value MUST be an ASCII string and MUST use percent-encoding for certain characters as specified in RFC3986 Section 2.1.
versionId	:Identifies a specific version of a DID document to be resolved (the version ID could be sequential, or a UUID, or method-specific). If present, the associated value MUST be an ASCII string.
versionTime	:Identifies a certain version timestamp of a DID document to be resolved. That is, the DID document that was valid for a DID at a certain time. If present, the associated value MUST be an ASCII string which is a valid XML datetime value, as defined in section 3.3.7 of W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes [XMLSCHEMA11-2]. This datetime value MUST be normalized to UTC 00:00:00 and without sub-second decimal precision. For example: 2020-12-20T19:17:47Z.
hl	:A resource hash of the DID document to add integrity protection, as specified in [HASHLINK]. This parameter is non-normative. If present, the associated value MUST be an ASCII string.

eg：
did:example:123?service=files&relativeRef=/resume.pdf
did:example:123?versionTime=2021-05-10T17:00:00Z
did:example:123?service=remoterpc#id1
'''


class DIDParams(BaseModel):
    service: Optional[str]
    relativeRef: Optional[str]
    versionId: Optional[str]
    versionTime: Optional[str]
    hl: Optional[str]

    def to_query(self):
        params = urlparse.urlencode(self.dict(exclude_none=True))
        qs = urlparse.parse_qs(params)
        return qs

    def to_str(self):
        params = urlparse.urlencode(self.dict(exclude_none=True))
        return params


'''
scheme:method:id/path?query=1&key=b#fragment
如： did:weid1001:0x11323232?query=1&key=abc#flagx1"
后半部分可用urllib.parse/parse_qs当做url处理
https://www.w3.org/TR/did-core/diagrams/parts-of-a-did.svg
'''


class DID:
    scheme = "did"
    method = "sample"
    id = ""
    url = None
    query = None
    params: DIDParams = DIDParams()

    def __init__(self, id="", scheme="did", method="weid", url=None):
        self.load(id, scheme, method, url)

    def detail(self):
        strdesc = f"scheme={self.scheme};method={self.method};id={self.id};url={self.url};query={self.query}"
        return strdesc

    def load(self, id, scheme="did", method="weid", url=None):
        self.id = id
        self.scheme = scheme
        self.method = method
        if url is not None:
            self.parse_url(url)

    def loads(didstr: str):
        didobj = DID()
        didpart = didstr
        urlpart = ""
        # print("didstr:",didstr)
        # 处理 did:weid101:0x123456/path/subpath?query=true&key=abc 有path的格式
        pos = didstr.find('/')
        if pos > 0:
            didpart = didstr[:pos]
            urlpart = didstr[pos:]
        else:
            # 处理 did:weid101:0x123456?query=true&key=abc 无path但带参数的格式
            pos = didstr.find('?')
            if pos > 0:
                didpart = didstr[:pos]
                urlpart = didstr[pos:]
        didobj.parse_did(didpart)
        didobj.parse_url(urlpart)
        return didobj

    def parse_did(self, didpart: str):
        # did:weid101:0x123456
        # did:weid101:test:0x123456 [test:0x123456]归为id部分，所以是split 2
        (self.scheme, self.method, self.id) = didpart.split(":", 2)

    def parse_url(self, url):
        # print("parse_url",url)
        self.url = urlparse.urlparse(url)
        self.query = urlparse.parse_qs(self.url.query)

    def dump_id(self):
        id = f"{self.scheme}:{self.method}:{self.id}"
        return id

    def dump(self):
        url = self.dump_url()
        alldata = f"{self.dump_id()}{url}"
        return alldata

    # 将did里的url.path+query+fragment(#xxxx)组合起来
    def dump_url(self):
        url = ""
        if self.url is not None:
            url = self.url.path
        if self.query is None:
            self.query = dict()
        self.query.update(self.params.to_query())
        params = urlparse.urlencode(self.query, doseq=True)  # query_qs解析出来的参数是数组，对应url里有多个同名key的情况，所以必须doseq=True
        if len(params) > 0:
            url = f"{url}?{params}"
        if self.url is not None and len(self.url.fragment) > 0:
            url = f"{url}#{self.url.fragment}"
        return url
